/*
 * DatabaseSubsystem.cpp
 *
 *  Created on: Apr 26, 2017
 *      Author: zhangjf
 */

#include <Poco/JSON/Parser.h>
#include <Poco/JSON/Object.h>
#include <Poco/Dynamic/Var.h>
#include <Poco/Data/SessionPool.h>
#include <Poco/Data/Session.h>
#include <Poco/Data/SQLite/Connector.h>
#include <Poco/Data/RecordSet.h>
#include <Poco/Data/Column.h>
#include <Poco/Data/MetaColumn.h>
#include <Poco/Data/DataException.h>
#include <Poco/Util/Application.h>

using namespace std;
using namespace Poco::Dynamic;
using namespace Poco::Data;
using namespace Poco::Data::SQLite;
using namespace Poco::Data::Keywords;
using namespace Poco::JSON;

using namespace Poco::Util;
using namespace Poco::Data;
using namespace Poco::Data::SQLite;

#include "Helper.h"
#include "DatabaseSubsystem.h"

using namespace util;

namespace database
{

const std::string DatabaseSubsystem::_name = "DatabaseSubsystem";
const std::string DatabaseSubsystem::_strDBDir = "/data/ncs/db";
const std::string DatabaseSubsystem::_strDBFileName = "ncs_test.sqlite";
const std::string DatabaseSubsystem::_strDBDirBak = "/data/original/db";
const std::vector<string> DatabaseSubsystem::_vecKnownCellFileType {
	"prop_list"
};

DatabaseSubsystem* DatabaseSubsystem::_pInstance = nullptr;

DatabaseSubsystem::DatabaseSubsystem()
: NCSSubsystem(name())
, _sessionPool()
{
	if (_pInstance != nullptr)
		return;
	_pInstance = this;

	// TODO Auto-generated constructor stub
	//std::string fname = std::string(Application::instance().name()) + ".log";
	//Helper::initLogger(logger(), fname);

	poco_information(logger(), __func__ + std::string(": ") + "ok");
}

DatabaseSubsystem::~DatabaseSubsystem()
{
	// TODO Auto-generated destructor stub
}

void DatabaseSubsystem::initialize(Application& self)
{
	// TODO initialize
	Poco::Data::SQLite::Connector::registerConnector();

	try
	{
		Path pathDB(_strDBDir, _strDBFileName);
		File fileDB(pathDB.toString());

		if (!fileDB.exists())
		{
			Path pathDBBak(_strDBDirBak, _strDBFileName);
			File fileDBBak(pathDBBak.toString());
			fileDBBak.copyTo(pathDB.toString());
		}
		_sessionPool = new SessionPool("SQLite", pathDB.toString());
	}
	catch(Poco::Data::DataException& exc)
	{
		poco_information(logger(), "Exception: " + exc.displayText());
	}
	poco_information(logger(), __func__ + std::string(": ") + "ok");
}

void DatabaseSubsystem::uninitialize()
{
	Poco::Data::SQLite::Connector::registerConnector();
}

/*
 * get the app count with the specific apptype
 * true: query success
 * false; error occurred when querying
 */
bool DatabaseSubsystem::getAppCountWithCellType(std::string& cellType, UInt32& counter)
{
	Session ses(_sessionPool->get());
	Statement statement(ses);
	bool blRet = false;

	try
	{
		statement << "SELECT count(i.app_id) FROM [tblCellApp] i WHERE i.cell_id IN (SELECT p.cell_id FROM tblRegisterCell p WHERE p.cell_type=?);", use(cellType), into(counter);
		statement.execute();
		blRet = true;
	}
	catch (Poco::Data::DataException& ce)
	{
		poco_information(logger(), "dberror: " + ce.displayText());	// fail (funct);
	}
	catch (...)
	{
		poco_information(logger(), "unknown exception");
	}

	return blRet;
}

bool DatabaseSubsystem::queryCellID(std::string& cellType, UInt32& cellID)
{
	bool blRet = true;
	try
	{
		cellID = (UInt32)-1;
		Session ses(_sessionPool->get());

		ses << "SELECT [cell_id] FROM [tblRegisterCell] WHERE [cell_type] = ?", into(cellID), use(cellType), now;
		if (cellID == (UInt32)-1)
		{
			blRet = false;
		}
	}
	catch (Exception& exc)
	{
		poco_information(logger(), exc.displayText());
		blRet = false;
	}

	return blRet;
}

bool DatabaseSubsystem::queryCellIDWithAppName(std::string& appName, UInt32& cellID)
{
	bool blRet = true;
	try
	{
		cellID = (UInt32)-1;
		Session ses(_sessionPool->get());

		ses << "SELECT [cell_id] FROM [tblCellApp] WHERE [app_name] = ?", into(cellID), use(appName), now;
		if (cellID == (UInt32)-1)
		{
			blRet = false;
		}
	}
	catch (Exception& exc)
	{
		poco_information(logger(), exc.displayText());
		blRet = false;
	}

	return blRet;
}

bool DatabaseSubsystem::queryAppID(std::string& appName, UInt32& appID)
{
	bool blRet = true;
	try
	{
		appID = (UInt32)-1;
		Session ses(_sessionPool->get());

		ses << "SELECT [app_id] FROM [tblCellApp] WHERE [app_name] = ?", into(appID), use(appName), now;
		if (appID == (UInt32)-1)
		{
			blRet = false;
		}
	}
	catch (Exception& exc)
	{
		poco_information(logger(), exc.displayText());
		blRet = false;
	}

	return blRet;
}

bool DatabaseSubsystem::isAppNameExist(std::string& appName)
{
	bool blRet = true;
	do
	{
		Session ses(_sessionPool->get());

		UInt32 count;
		ses << "SELECT count([app_id]) FROM [tblCellApp] WHERE [app_name] = ?", into(count), use(appName), now;

		if (count == 0)
			blRet = false;

	} while(false);

	return blRet;
}

// check the celltype has registered in database
bool DatabaseSubsystem::isRegisterCellType(std::string& cellType)
{
	bool blRet = true;
	try
	{
		Session ses(_sessionPool->get());

		UInt32 count;
		ses << "SELECT count([cell_id]) FROM [tblRegisterCell] WHERE [cell_type] = ?", into(count), use(cellType), now;

		if (count == 0)
			blRet = false;
	}
	catch (Exception& exc)
	{
		poco_information(logger(), exc.displayText());
		blRet = false;
	}

	return blRet;
}

bool DatabaseSubsystem::registerCell(std::string& cellType, Object::Ptr& joCellInfo, UInt32& cellID)
{
	bool blRet = true;
	do
	{
		Session ses(_sessionPool->get());

		Object::Ptr joCellFiles = joCellInfo->getObject("cell_files");
		ostringstream oss;
		joCellFiles->stringify(oss);
		string cellFiles = oss.str();

		poco_information(logger(), cellType + "," + cellFiles);
		ses << "INSERT INTO [tblRegisterCell]([cell_type], [cell_files]) VALUES(?, ?)", use(cellType), use(cellFiles), now;

		ses << "SELECT [cell_id] FROM [tblRegisterCell] WHERE [cell_type] = ?", into(cellID), use(cellType), now;
	} while (false);

	return blRet;
}

bool DatabaseSubsystem::registerCellInfo(std::string& cellType, Object::Ptr& joCellInfo, UInt32& cellID)
{
	bool blRet = true;
	do
	{
		Session ses(_sessionPool->get());

		Object::Ptr joInfo = joCellInfo->getObject("cell_info");
		string version = joInfo->getValue<string>("version");
		string company = joInfo->getValue<string>("company");
		string product = joInfo->getValue<string>("product");
		string description = joInfo->getValue<string>("description");
		string cell_class = joInfo->getValue<string>("cell_class");
		ostringstream oss;
		joInfo->getArray("attributes")->stringify(oss);
		string attributes = oss.str();
		int max_instances = joInfo->getValue<int>("max_instances");
		//poco_information(logger(), std::to_string(cellID) + "," + version + "," + company + "," + product + "," + description + "," + cell_class + "," + attributes + "," + to_string(max_instances));
		ses << "INSERT INTO [tblCellInfo]([cell_id], [version], [company], [product], [description], [cell_class], [attributes], [max_instances]) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
				use(cellID), use(version), use(company), use(product), use(description), use(cell_class), use(attributes), use(max_instances), now;
	} while(false);

	return blRet;
}

bool DatabaseSubsystem::registerCellFiles(std::string& cellType, string& zipFile, Object::Ptr& joCellInfo)
{
	bool blRet = true;
	do
	{
		Session ses(_sessionPool->get());

		Object::Ptr joCellFiles = joCellInfo->getObject("cell_files");

		string strBuf;
		for (auto item : *joCellFiles)
		{
			string subFileName = item.second.toString();
			Helper::readFileFromZip(zipFile, subFileName, strBuf);
			//poco_information(logger(), strBuf);

			if (item.first == "prop_list")
			{
				Parser parser;
				Object::Ptr joCellProperties= parser.parse(strBuf).extract<Object::Ptr>();

				if (importCellProperties(cellType, joCellProperties) == false)
				{
					poco_information(logger(), "error: importCellProperties() failed");
					blRet = false;
				}
			}
			else
			{
				poco_information(logger(), "unknown cell file type: " + item.first);
				blRet = false;
				break;
			}
		}
	} while(false);

	return blRet;
}

bool DatabaseSubsystem::importCellProperties(std::string& cellType, Object::Ptr& joCellProperties)
{
	bool blRet = true;

	do
	{
		Session ses(_sessionPool->get());
		std::ostringstream oss;
		std::string strTableName;
		if (makeCellPropTableName(cellType, strTableName) == false)
		{
			blRet = false;
			break;
		}

		oss << "CREATE TABLE [" << strTableName << "]("
		    << "[prop_id] VARCHAR(64) PRIMARY KEY ASC NOT NULL UNIQUE, "
		    << "[prop_name] VARCHAR(128) NOT NULL UNIQUE, "
		    << "[description] VARCHAR(256), "
		    << "[function] VARCHAR(16) NOT NULL, "
		    << "[attribute] VARCHAR(1024) DEFAULT [], "
		    << "[data_type] VARCHAR(16) NOT NULL DEFAULT str, "
		    << "[eu_catagory] VARCHAR(16) NOT NULL DEFAULT no_cat, "
		    << "[precision] TINYINT DEFAULT 0, "
		    << "[default] VARCHAR(256), "
		    << "[min] VARCHAR(256), "
		    << "[max] VARCHAR(256), "
		    << "[visibility] VARCHAR(16) DEFAULT basic, "
		    << "[v-condition] VARCHAR(1024), "
		    << "[helper] VARCHAR(8192));";
		ses << oss.str(), now;

		JSON::Array::Ptr properies = joCellProperties->getArray("properties");
		std::string strInsertHeader = "INSERT INTO [" + strTableName + "](";
		//poco_information(logger(), strInsertHeader);
		for (auto item : *properies)
		{
			ostringstream oss1;
			//map<string, Var> mapPropItem;
			Object::Ptr joProp = item.extract<Object::Ptr>();

			std::vector<std::string> vecKeys;
			std::vector<std::string> vecValues;

			//vecKeys.push_back("[cell_id]");
			//vecValues.push_back(to_string(cellID));
			for (auto sub : *joProp)
			{
				vecKeys.push_back("[" + sub.first + "]");
				std::string str;
				if (sub.second.isString())
				{
					str = sub.second.toString();
				}
				else if (sub.second.isInteger())
				{
					str = sub.second.toString();
				}
				else
				{
					if (sub.first == "helper")
					{
						JSON::Object::Ptr val = sub.second.extract<JSON::Object::Ptr>();
						ostringstream oss;
						val->stringify(oss);
						str = oss.str();
					}
					else
					{
						JSON::Array::Ptr val = sub.second.extract<JSON::Array::Ptr>();
						ostringstream oss;
						val->stringify(oss);
						str = oss.str();
					}
				}
				vecValues.push_back("'" + str + "'");
			}

			std::string strSep = ", ";
			string str1 = Helper::joinStrings(vecKeys, strSep);
			//poco_information(logger(), str1);
			string str2 = Helper::joinStrings(vecValues, strSep);
			//poco_information(logger(), str2);

			oss1 << strInsertHeader << str1 << ") VALUES(" << str2 << ")";
			//std::string strStatement = std::string("INSERT INTO [tblCellProp](") + str1 + ") VALUES(" + str2 + ")";
			//poco_information(logger(), oss1.str());
			ses << oss1.str(), now;
		}
	}  while(false);

	return blRet;
}

bool DatabaseSubsystem::registerCellType(std::string& cellType, string& zipFile, Object::Ptr& joCellInfo)
{
	bool blRet = true;
	try
	{
		Session ses(_sessionPool->get());

		UInt32 cellID;
		registerCell(cellType, joCellInfo, cellID);
		registerCellInfo(cellType, joCellInfo, cellID);
		registerCellFiles(cellType, zipFile, joCellInfo);
		blRet = true;
	}
	catch (Exception& exc)
	{
		poco_information(logger(), exc.displayText());
		blRet = false;
	}

	return blRet;
}

bool DatabaseSubsystem::makeCellPropTableName(std::string& cellType, std::string& strTableName)
{
	bool blRet = false;

	UInt32 cellID;
	if (queryCellID(cellType, cellID))
	{
		poco_information(logger(), std::string(__func__) + ", " + std::to_string(__LINE__) + "aaaaaaaaaaaaaaaa");
		//throw Data::DataException("error: queryCellID() failed:" + cellType);
		strTableName = makeTableNameWithID("tblCellProp", cellID);
		blRet = true;
	}

	return blRet;
}

bool DatabaseSubsystem::makeCellPropTableNameWithAppName(std::string& appName, std::string& strTableName)
{
	bool blRet = false;

	UInt32 cellID;

	if (queryCellIDWithAppName(appName, cellID))
	{
		poco_information(logger(), std::string(__func__) + ", " + std::to_string(__LINE__) + "aaaaaaaaaaaaaaaa");
		//throw Data::DataException("error: queryCellIDWithAppName() failed:" + appName);
		strTableName = makeTableNameWithID("tblCellProp", cellID);
		blRet = true;
	}

	return blRet;
}

bool DatabaseSubsystem::makeAppPropTableName(std::string& appName, std::string& strTableName)
{
	bool blRet = false;
	UInt32 appID;
	if (queryAppID(appName, appID))
	{
		poco_information(logger(), std::string(__func__) + ", " + std::to_string(__LINE__) + "aaaaaaaaaaaaaaaa");
		//throw Data::DataException("error: queryAppID() failed:" + appName);
		strTableName = makeTableNameWithID("tblAppProp", appID);
		blRet = true;
	}

	return blRet;
}

std::string DatabaseSubsystem::makeTableNameWithID(const std::string& prefix, UInt32 id)
{
	char buff[128];
	sprintf(buff, "%s_%03d", prefix.c_str(), id);
	return std::string(buff);
}

bool DatabaseSubsystem::addApp(std::string& cellType, std::string& appName, UInt32& appID)
{
	bool blRet = true;
	try
	{
		UInt32 cellID;
		queryCellID(cellType, cellID);
		Session ses(_sessionPool->get());

		if (appName.empty())
		{
			getFreeAppName(cellType, appName);
		}

		ses << "INSERT INTO [tblCellApp](cell_id, app_name) VALUES(?, ?)", use(cellID), use(appName), now;
		ses << "SELECT [app_id] FROM [tblCellApp] WHERE [app_name] = ?", into(appID), use(appName), now;

		std::string strAppTableName = makeTableNameWithID("tblAppProp", appID);
		std::string strCellTableName = makeTableNameWithID("tblCellProp", cellID);

		ostringstream oss;
		oss << "CREATE TABLE [" << strAppTableName << "]("
		    << "[prop_id] VARCHAR(64) NOT NULL REFERENCES " <<  strCellTableName << "([prop_id]), "
		    << "[data_type] VARCHAR(16) NOT NULL DEFAULT str, "
		    << "[eu_catagory] VARCHAR(32) NOT NULL DEFAULT no_cat, "
		    << "[precision] TINYINT DEFAULT 0, "
		    << "[value] VARCHAR(256), "
		    << "[min] VARCHAR(256), "
		    << "[max] VARCHAR(256), "
		    << "[helper] VARCHAR(8192));";
		//poco_information(logger(), oss.str());
		ses << oss.str(), now;

		std::string strStatement = "SELECT [prop_id], [data_type], [eu_catagory], [precision], [default], [min], [max], [helper] FROM [" + strCellTableName + "]";
		Statement stmt = (ses << strStatement);
		stmt.execute();
		RecordSet rs(stmt);

		Session ses1(_sessionPool->get());
		std::string strInsert = "INSERT INTO [" + strAppTableName + "](";
		bool more = rs.moveFirst();
		while (more)
		{
			ostringstream oss1;
			std::vector<std::string> vecKeys;
			std::vector<std::string> vecValues;

			UInt32 i = 0;
			for (; i < rs.columnCount(); ++i)
			{
				const std::string& strColName = rs.columnName(i);
				if (!rs.isNull(strColName))
				{
					//poco_information(logger(), strColName);
					//poco_information(logger(), rs[strColName].toString());
					if (strColName == "default")
					{
						vecKeys.push_back("[value]");
						vecValues.push_back("'" + rs["default"] + "'");
					}
					else
					{
						vecKeys.push_back("[" + strColName + "]");
						vecValues.push_back("'" + rs[strColName] + "'");
					}
				}
			}

			std::string strSep = ", ";
			string str1 = Helper::joinStrings(vecKeys, strSep);
			//poco_information(logger(), str1);
			string str2 = Helper::joinStrings(vecValues, strSep);

			oss1 << strInsert << str1 << ") VALUES(" << str2 << ")";
			//poco_information(logger(), oss1.str());
			ses1 << oss1.str(), now;

			more = rs.moveNext();
		}

		blRet = true;
	}
	catch (Exception& exc)
	{
		poco_information(logger(), exc.displayText());
		blRet = false;
	}

	return blRet;
}

bool DatabaseSubsystem::getFreeAppName(std::string& cellType, std::string& appName)
{
	bool blRet = true;
	try
	{
		std::vector<std::string> vecAppNames;
		getFreeAppNames(cellType, vecAppNames, 1);
		appName = vecAppNames[0];

		blRet = true;
	}
	catch (Exception& exc)
	{
		poco_information(logger(), exc.displayText());
		blRet = false;
	}

	return blRet;
}

bool DatabaseSubsystem::getFreeAppNames(std::string& cellType, std::vector<std::string>& vecAppNames, UInt32 num)
{
	bool blRet = true;
	try
	{
		Session ses(_sessionPool->get());

		std::vector<std::string> names;
		ses << "SELECT [app_name] FROM [tblCellApp] WHERE [cell_id] in (SELECT [cell_id] FROM [tblRegisterCell] WHERE [cell_type] == ?)", use(cellType), into(names);

		UInt32 i = 1, count = 0;
		char buff[128];
		for (; num > 0; num--)
		{
			do
			{
				sprintf(buff, "%s_%03d", cellType.c_str(), i);
				std::string strName(buff);
				if (!isAppNameExist(strName))
				{
					vecAppNames.push_back(strName);
					count++;
					break;
				}
				i++;
			} while (true);
		}
		blRet = true;
	}
	catch (Exception& exc)
	{
		poco_information(logger(), exc.displayText());
		blRet = false;
	}

	return blRet;
}

bool DatabaseSubsystem::getCellTypeList(std::vector<std::string>& vecCellType)
{
	bool blRet = true;

	do
	{
		Session ses(_sessionPool->get());

		ses << "SELECT [cell_type] FROM [tblRegisterCell]", into(vecCellType), now;

	}  while(false);

	return blRet;
}

bool DatabaseSubsystem::getAppList(std::vector<std::string>& vecApp)
{
	bool blRet = true;

	do
	{
		Session ses(_sessionPool->get());

		std::vector<std::string> vecCellType;
		std::vector<std::string> vecAppName;
		ses << "SELECT a.[app_name], b.[cell_type] FROM [tblCellApp] a, [tblRegisterCell] b WHERE a.[cell_id] == b.[cell_id]", into(vecAppName), into(vecCellType), now;

		std::vector<std::string>::size_type i = 0;
		for (; i < vecAppName.size(); ++i)
		{
			vecApp.push_back(vecCellType[i] + ":" + vecAppName[i]);
		}
	}  while(false);

	return blRet;
}

bool DatabaseSubsystem::getAppProperties(std::string& strAppName, JSON::Array& jaProps, std::string& strError)
{
	bool blRet = true;

	//poco_information(logger(), "enter DatabaseSubsystem::getAppProperties()");
	do
	{
		Session ses(_sessionPool->get());

		//poco_information(logger(), "app name : " + strAppName);
		if (checkAppName(strAppName) == false)
		{
			strError = "app name(" + strAppName + ") is invalid";
			poco_information(logger(), std::string(__func__) + ", " + std::to_string(__LINE__) + ": " + strError);
			blRet = false;
			break;
		}

		string tblNameCellProp, tblNameAppProp;
		if (!(makeCellPropTableNameWithAppName(strAppName, tblNameCellProp) && makeAppPropTableName(strAppName, tblNameAppProp)))
		{
			strError = "Not found the app name(" + strAppName + ") in database";
			poco_information(logger(), std::string(__func__) + ", " + std::to_string(__LINE__) + ": " + strError);
			blRet = false;
			break;
		}

		std::ostringstream oss;
		oss << "SELECT  a.[prop_id], a.[data_type], a.[eu_catagory], a.[precision], a.[max], a.[min], a.[value], a.[helper], "
			<< "b.[prop_name], b.[description], b.[function], b.[attribute], b.[default], b.[visibility], b.[v-condition] "
			<< "FROM 	[" << tblNameAppProp << "] AS a, [" << tblNameCellProp << "] AS b "
			<< "WHERE 	a.[prop_id] = b.[prop_id]";

		Statement stmt = (ses << oss.str());
		stmt.execute();
		RecordSet rs(stmt);

		if (rs.rowCount() <= 0)
		{
			strError = "Query properties of app name(" + strAppName + ") in database failed";
			poco_information(logger(), std::string(__func__) + ", " + std::to_string(__LINE__) + ": " + strError);
			break;
			blRet = false;
		}

		bool more = rs.moveFirst();
		Poco::JSON::Parser parser;
		while (more)
		{
			UInt32 i = 0;
			Object joPropItem;
			for (; i < rs.columnCount(); ++i)
			{
				parser.reset();	//remember:: repeate using the parser, please reset it!!!
				const std::string& strColName = rs.columnName(i);

				if (!rs.isNull(strColName))
				{
					//poco_information(logger(), "col: " + std::to_string(i) + ": " + strColName + " is not null");
					//poco_information(logger(), "col: " + std::to_string(i) + " type: " + std::to_string(rs.columnType(i)));
					//poco_information(logger(), "col: " + std::to_string(i) + " value: " + rs.value(i).toString());
					switch (rs.columnType(i))
					{
					case MetaColumn::FDT_BOOL:
						joPropItem.set(strColName, rs.nvl<bool>(i));
						break;
					case MetaColumn::FDT_INT8:
					case MetaColumn::FDT_INT16:
					case MetaColumn::FDT_INT32:
					case MetaColumn::FDT_INT64:
						joPropItem.set(strColName, rs.nvl<Int32>(i));
						break;
					case MetaColumn::FDT_UINT8:
					case MetaColumn::FDT_UINT16:
					case MetaColumn::FDT_UINT32:
					case MetaColumn::FDT_UINT64:
						joPropItem.set(strColName, rs.nvl<UInt32>(i));
						break;
					case MetaColumn::FDT_FLOAT:
					case MetaColumn::FDT_DOUBLE:
						joPropItem.set(strColName, rs.nvl<float>(i));
						break;
					case MetaColumn::FDT_STRING:
						{
							std::string tmp = rs.value(i).toString();
							//poco_information(logger(), tmp);
							if (((tmp[0] == '[') && (tmp[tmp.length() - 1] == ']'))
									|| ((tmp[0] == '{') && (tmp[tmp.length() - 1] == '}')))
							{
								joPropItem.set(strColName, parser.parse(tmp));
							}
							else
							{
								joPropItem.set(strColName, tmp);
							}
						}
						break;
					case MetaColumn::FDT_DATE:
					case MetaColumn::FDT_TIME:
						// TODO
						//joPropItem[strColName] = rs.nvl<std::string>(i);
						poco_information(logger(), std::string(__func__) + ", " + std::to_string(__LINE__) + ": unhandled exception occurred");
						break;
					case MetaColumn::FDT_TIMESTAMP:
						// TODO
						//joPropItem[strColName] = rs.nvl<std::string>(i);
						poco_information(logger(), std::string(__func__) + ", " + std::to_string(__LINE__) + ": unhandled exception occurred");
						break;
					case MetaColumn::FDT_WSTRING:
					case MetaColumn::FDT_BLOB:
					case MetaColumn::FDT_CLOB:
					case MetaColumn::FDT_UNKNOWN:
						poco_information(logger(), std::string(__func__) + ", " + std::to_string(__LINE__) + ": unhandled exception occurred");
						break;
					}
				}
				else
				{
					//poco_information(logger(), "col: " + std::to_string(i) + ": " + strColName + "isNull()");

				}
			}
			jaProps.add(joPropItem);

			more = rs.moveNext();
		}
	}  while(false);
	//poco_information(logger(), "leave DatabaseSubsystem::getAppProperties()");

	return blRet;
}

bool DatabaseSubsystem::checkAppName(std::string& strAppName)
{
	bool blRet = false;

	std::string::size_type pos = strAppName.find_first_not_of("1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_");
	if (pos == std::string::npos)
	{
		blRet = true;
	}

	return blRet;
}

} /* namespace database */

